package com.tdcy.framework.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;

import com.tdcy.framework.annotation.Column;
import com.tdcy.framework.exception.BaseException;

public class BeanUtil {
	static {
		ConvertUtils.register(new DateConvert(), java.util.Date.class);
		ConvertUtils.register(new DateConvert(), java.sql.Date.class);
	}
	
	/**
	 * 从源对象注入新对象
	 * 
	 * @param src
	 * @param dest
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T injectObject(Object src, Object dest) {
		Class<? extends Object> srcClz = src.getClass();
		Class<? extends Object> destClz = dest.getClass();
		List<Field> fs = ReflectUtils.getClassFields(destClz, true);
		for (Field f : fs) {
			String fieldName = f.getName();
			if (fieldName.equalsIgnoreCase("serialVersionUID")) {
				continue;
			}
			String setMethod = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
			String getMethod = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
			try {
				Method srcm = srcClz.getMethod(getMethod);
				Object returnObj = srcm.invoke(src);
				if (returnObj == null) {
					continue;
				}
				Method destm = destClz.getMethod(setMethod, returnObj.getClass());
				destm.invoke(dest, returnObj);
			} catch (java.lang.NoSuchMethodException e) {
				continue;
			} catch (Exception e) {
				throw new BaseException("反射调用失败", e);
			}
		}

		return (T) dest;
	}

	/**
	 * 将多种源对象的值设到新对象
	 * 
	 * @param dest
	 * @param src
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T mergeObject(Object dest, Object... srcs) {

		Class<? extends Object> destClz = dest.getClass();
		Field[] fs = destClz.getDeclaredFields();
		for (Field f : fs) {
			String fieldName = f.getName();
			if (fieldName.equalsIgnoreCase("serialVersionUID")) {
				continue;
			}
			String setMethod = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
			String getMethod = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
			Object returnObj = null;
			try {
				for (Object src : srcs) {
					try {
						if (src == null) {
							continue;
						}
						Class<? extends Object> srcClz = src.getClass();
						Method srcm = srcClz.getMethod(getMethod);
						returnObj = srcm.invoke(src);
						if (returnObj != null) {
							break;
						}
					} catch (NoSuchMethodException ee) {// 该对象不存在此方法
						continue;
					}
				}
				if (returnObj == null) {
					continue;
				}
				Method destm = destClz.getMethod(setMethod, returnObj.getClass());
				destm.invoke(dest, returnObj);

			} catch (Exception e) {
				e.printStackTrace();
				throw new BaseException("反射调用失败", e);
			}
		}

		return (T) dest;
	}

	public static void copyProperties(Map<String, Object> paraMap, Object obj) {
		try {
			List<Field> fields = ReflectUtils.getClassFields(obj.getClass(), true);
			for (int i = 0; i < fields.size(); i++) {
				Field field = fields.get(i);
				boolean hasAnnotation = field.isAnnotationPresent(Column.class);
				if (hasAnnotation) {
					Column annotation = (Column) field.getAnnotation(Column.class);
					String an = annotation.name().toLowerCase();
					String fn = field.getName();

					if (paraMap.get(an) != null) {
						BeanUtils.setProperty(obj, fn, paraMap.get(an));
					}
				}
			}
		} catch (IllegalAccessException  e) {
			e.printStackTrace();
		}catch ( InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	public static void toBean(Map m, Object c) {
		try {
			BeanUtils.populate(c, m);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BaseException("复制属性出错", e);
		}
	}

	public static Map<String, String> toMap(Object object) {
		try {
			return BeanUtils.describe(object);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BaseException("复制属性出错", e);
		}
	}

	public static List<Map<String, String>> toListMap(List<Object> obj) {
		List<Map<String, String>> list = new ArrayList<Map<String, String>>();
		for (Object o : obj) {
			Map<String, String> tm = toMap(o);
			list.add(tm);
		}
		return list;
	}

}

class DateConvert implements Converter {
	public Object convert(Class type, Object value) {
		if (value == null) {
			return null;
		} else if (type == Timestamp.class) {
			return convertToDate(type, value, "yyyy-MM-dd HH:mm:ss");
		} else if (type == Date.class) {
			return convertToDate(type, value, "yyyy-MM-dd");
		} else if (type == String.class) {
			return convertToString(type, value);
		}

		throw new ConversionException("不能转换 " + value.getClass().getName() + " 为 " + type.getName());
	}

	protected Object convertToDate(Class type, Object value, String pattern) {
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		if (value instanceof String) {
			try {
				if (StringUtils.isEmpty(value.toString())) {
					return null;
				}
				Date date = sdf.parse((String) value);
				if (type.equals(Timestamp.class)) {
					return new Timestamp(date.getTime());
				}
				return date;
			} catch (Exception pe) {
				return null;
			}
		} else if (value instanceof Date) {
			return value;
		}

		throw new ConversionException("不能转换 " + value.getClass().getName() + " 为 " + type.getName());
	}

	protected Object convertToString(Class type, Object value) {
		if (value instanceof Date) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

			if (value instanceof Timestamp) {
				sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			}

			try {
				return sdf.format(value);
			} catch (Exception e) {
				throw new ConversionException("日期转换为字符串时出错！");
			}
		} else {
			return value.toString();
		}
	}

}
